package com.jack.online.study.config.datasource;


import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.jack.online.study.handler.CommonMetaObjectHandler;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import jakarta.annotation.Resource;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

@Configuration
@MapperScan(basePackages = MysqlDataSourceConfig.PACKAGE,sqlSessionTemplateRef = "mysqlSqlSessionTemplate")
public class MysqlDataSourceConfig {

    /**
     * 注入mybatisPlus自动填充处理器
     */
    @Resource
    public MetaObjectHandler metaObjectHandler;
    /**
     * 设置扫描包的路径
     */
    public static final String PACKAGE = "com.jack.online.study.mapper";
    /**
     * Mapper配置文件路径
     */
    public static final String MAPPER_LOCATION = "classpath*:mapper/mysql/*/*.xml";

    /**
     * 实体别名
     */
    public static final String ENTITY_ALIASES = "com.jack.online.study.model/dao";

    @Value("${spring.datasource.mysql.driver-class-name}")
    private String driverClassName;

    @Value("${spring.datasource.mysql.url}")
    private String url;

    @Value("${spring.datasource.mysql.username}")
    private String user;

    @Value("${spring.datasource.mysql.password}")
    private String password;


    /**
     * 创建数据源
     * @return DataSource
     * Primary 用于指定bean的注入优先级。被@Primary修饰的bean对象优先注入
     */
    @Bean(name = "mysqlDataSource")
    @Primary
    public DataSource mysqlDataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(url);
        config.setUsername(user);
        config.setPassword(password);
        config.setDriverClassName(driverClassName);
        // 设置其他属性
        config.setMaximumPoolSize(10); // 设置最大连接数
        config.setConnectionTimeout(30000); // 设置连接超时时间
        // 测试连接的指令，如果提供了这个查询，那么在每次从连接池中获取连接之前，都会使用这个查询来测试连接的有效性。如果查询失败，则认为该连接已经过期并将其从池中移除。
        config.setConnectionTestQuery("SELECT 1");
        // 创建Hikari数据源
        return new HikariDataSource(config);
    }


    /**
     * 创建工厂
     */
    @Bean(name = "mysqlSqlSessionFactory")
    @Primary
    public SqlSessionFactory masterSqlSessionFactory(@Qualifier("mysqlDataSource") DataSource dataSource) throws Exception {
        //mybatisPlus提供的类
        MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION));
        sessionFactory.setTypeAliasesPackage(ENTITY_ALIASES);
        //配置mybatisPlus的额外配置
        MybatisConfiguration configuration = new MybatisConfiguration();
        // 字段值为空也可以插入
        configuration.setJdbcTypeForNull(JdbcType.NULL);
        configuration.setCallSettersOnNulls(true);
        // mybatis log打印sql语句
        configuration.setLogImpl(StdOutImpl.class);
        // 开启下划线转驼峰映射
        configuration.setMapUnderscoreToCamelCase(true);
        sessionFactory.setConfiguration(configuration);

        //插件对象,分页
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        //乐观锁插件
        OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor = new OptimisticLockerInnerInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        mybatisPlusInterceptor.addInnerInterceptor(optimisticLockerInnerInterceptor);
        //全局配置，自动填充
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setMetaObjectHandler(metaObjectHandler);

        sessionFactory.setPlugins(mybatisPlusInterceptor);
        sessionFactory.setGlobalConfig(globalConfig);
        return sessionFactory.getObject();
    }

    /**
     * 创建事务
     */
    @Bean(name = "mysqlTransactionManager")
    @Primary
    public DataSourceTransactionManager masterDataSourceTransactionManager(@Qualifier("mysqlDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    /**
     * 创建模板
     */
    @Bean(name = "mysqlSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate masterSqlSessionTemplate(@Qualifier("mysqlSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

}
